ATOM Documentation

← Back to App

Screen Reader Testing Procedures

**Purpose:** Verify NVDA (Windows) and VoiceOver (macOS) compatibility for WCAG 2.1 AA compliance

**Schedule:** Quarterly audits, before major releases, when introducing new UI patterns

**Tools:**

  • **NVDA** (Windows) - Free, open source screen reader
  • **VoiceOver** (macOS) - Built-in screen reader

**Why This Matters:**

Automated accessibility tools catch ~70% of WCAG violations, but cannot verify:

  • Are announcements clear and helpful?
  • Is navigation efficient?
  • Do dynamic updates announce properly?
  • Is the screen reader experience actually usable?

---

NVDA Testing (Windows)

Setup

  1. **Install NVDA:**
  • Download from https://www.nvaccess.org/download/
  • Install with default settings
  • Launch NVDA (Ctrl+Alt+N, or from Start Menu)
  1. **Configure Settings:**
  • Use default speech settings
  • Ensure "Speech Mode" is set to "Talk"
  • Set "Braille" to "No braille" (unless using braille display)
  1. **Choose Browser:**
  • **Firefox** (recommended) - Best NVDA compatibility
  • **Chrome** (acceptable) - Good support, but Firefox preferred
  • **Edge** (acceptable) - Generally good support
  1. **Test Environment:**
  • Test on Windows 10 or 11
  • Use external speakers or headphones
  • Ensure volume is audible but not uncomfortable

Key NVDA Commands

**Global Commands (work in any application):**

CommandActionNotes
Ctrl+Alt+NLaunch NVDAStarts screen reader
NVDA+QQuit NVDAPrompts to confirm exit
NVDA+Ctrl+SToggle speechSilence/resume speech
NVDA+Ctrl+RRestart NVDAReload NVDA settings

**Navigation Commands (in browser):**

CommandActionNotes
NVDA+DownRead allStart reading from current position
NVDA+UpPrevious lineMove focus and read previous line
NVDA+KRead current lineRead current focused line
NVDA+BRead all from topStart reading from page beginning
NVDA+LRead current line (alternate)Different annunciation

**Heading Navigation:**

CommandActionNotes
HNext headingJump to next heading at any level
Shift+HPrevious headingJump to previous heading
1-6Jump to heading levelPress number for specific level
NVDA+F7Elements listShows all headings, links, landmarks

**Landmark Navigation:**

CommandActionNotes
NVDA+DLandmarks listShows all ARIA landmarks
DNext landmarkJump to next landmark
Shift+DPrevious landmarkJump to previous landmark

**Table Navigation:**

CommandActionNotes
TNext tableJump to next table
Shift+TPrevious tableJump to previous table
Ctrl+Alt+ArrowsNavigate table cellsMove between cells
NVDA+F5Read table headersAnnounce column/row headers

**Form Navigation:**

CommandActionNotes
FNext form fieldJump to next input
Shift+FPrevious form fieldJump to previous input
NVDA+SpaceActivateActivate button/checkbox
EnterSubmitSubmit form or activate link
SpaceToggleToggle checkbox/radio button

**Focus and Object Navigation:**

CommandActionNotes
TabNext focusableMove to next focusable element
Shift+TabPrevious focusableMove to previous focusable
NVDA+F8Current objectGet details about focused object
NVDA+Numpad5Read objectRead current object properties
NVDA+Numpad8Read object and typeObject type and state

**Note:** NVDA key = Insert key (may be CapsLock on some keyboards)

Test Scenarios for NVDA

1. Page Load

**Test Steps:**

  1. Navigate to page URL
  2. Press NVDA+B to read from top
  3. Listen to announcements

**Expected Results:**

  • [ ] Page title announced immediately
  • [ ] Main content landmark announced
  • [ ] Number of landmarks announced (if configured)
  • [ ] Heading level 1 (page title) announced
  • [ ] Language attribute announced (if non-English)

**Common Issues:**

  • ❌ No page title → Add <title>Page Name</title> to <head>
  • ❌ No landmarks → Add <main>, <nav>, <header>, <footer> regions
  • ❌ No h1 → Add single <h1> for page title

2. Navigation by Headings

**Test Steps:**

  1. Press H to jump through headings
  2. Press 1-6 to jump to specific heading levels
  3. Press NVDA+F7 to open elements list, then choose "Headings"

**Expected Results:**

  • [ ] Heading level announced correctly (h1, h2, h3, etc.)
  • [ ] Heading text announced clearly
  • [ ] Heading hierarchy makes sense (no skipped levels)
  • [ ] Headings provide good navigation structure

**Common Issues:**

  • ❌ Skipped heading levels (h1 → h3) → Add missing h2
  • ❌ Headings used for styling → Use CSS classes, not heading tags
  • ❌ Vague headings → Use descriptive headings

3. Navigation by Landmarks

**Test Steps:**

  1. Press NVDA+D to open landmarks list
  2. Choose landmark from list
  3. Press D and Shift+D to cycle through landmarks

**Expected Results:**

  • [ ] All major regions have landmarks (banner, nav, main, footer)
  • [ ] Landmark names are descriptive (not "region")
  • [ ] Multiple landmarks of same type have labels (e.g., "Primary navigation", "Footer navigation")
  • [ ] Can jump directly to any major region

**Common Issues:**

  • ❌ Missing landmarks → Add <nav>, <main>, <aside> with aria-label
  • ❌ Generic "region" landmarks → Add aria-label to identify purpose
  • ❌ Nested landmarks → Flatten structure where possible

4. Forms

**Test Steps:**

  1. Navigate to form (using landmarks or headings)
  2. Press F to jump between form fields
  3. Fill out form using keyboard only
  4. Submit form

**Expected Results:**

  • [ ] Each input has visible label announced before input
  • [ ] Required fields indicated ("required", "star", etc.)
  • [ ] Placeholder text is NOT announced as label (placeholder ≠ label)
  • [ ] Error messages announced immediately after invalid submission
  • [ ] Validation feedback provided (inline errors, aria-invalid)
  • [ ] Form can be completed without mouse

**Common Issues:**

  • ❌ Missing labels → Add <label for="id">Label Text</label> + id="id" on input
  • ❌ Placeholder as label → Add proper label element
  • ❌ Errors not announced → Add role="alert" or aria-live="polite" to error messages
  • ❌ Required not indicated → Add aria-required="true" + visual indicator

5. Dynamic Content (Modals, Toasts, Live Updates)

**Test Steps:**

  1. Open modal (trigger action)
  2. Listen to announcement
  3. Close modal
  4. Observe focus behavior
  5. Trigger toast/notification
  6. Trigger dynamic content update (e.g., search results)

**Expected Results:**

  • [ ] Modal open announced ("dialog appeared", or custom message)
  • [ ] Focus moves into modal (trap focus)
  • [ ] Modal close announced
  • [ ] Focus returns to trigger element after close
  • [ ] Toast notifications announced (aria-live region)
  • [ ] Loading states announced ("loading...", "loaded")
  • [ ] New items in lists announced

**Common Issues:**

  • ❌ Modal not announced → Add role="dialog" + aria-modal="true" + aria-labelledby
  • ❌ Focus not trapped → Implement focus trap in modal
  • ❌ Focus not returned → Restore focus to trigger on close
  • ❌ Toast not announced → Add role="status" or role="alert" + aria-live
  • ❌ Loading not announced → Add aria-live="polite" to loading indicator

6. Tables

**Test Steps:**

  1. Navigate to table (press T)
  2. Press Ctrl+Alt+Arrows to navigate cells
  3. Press NVDA+F5 to read headers

**Expected Results:**

  • [ ] Table purpose announced ("table with X columns")
  • [ ] Column/row headers announced when navigating
  • [ ] Cell coordinates announced (optional but helpful)
  • [ ] Can navigate entire table with keyboard
  • [ ] Data tables have <th> elements with scope attributes

**Common Issues:**

  • ❌ No headers → Add <th scope="col"> or <th scope="row">
  • ❌ Layout table announced as data → Add role="presentation" to layout tables
  • ❌ Nested tables → Flatten to single table if possible

**Test Steps:**

  1. Navigate through page using Tab
  2. Listen to link/button announcements
  3. Visit NVDA+F7 → "Links" to see all links

**Expected Results:**

  • [ ] Link destination is clear from text or aria-label
  • [ ] "Click here" links avoided (use descriptive text)
  • [ ] Icon-only buttons have aria-label
  • [ ] Button purpose announced (e.g., "Submit button", "Close button")
  • [ ] Link vs button distinguished appropriately

**Common Issues:**

  • ❌ "Click here" links → Use descriptive link text: "Download pricing PDF"
  • ❌ Icon button no label → Add aria-label="Close dialog" to icon button
  • ❌ Link used as button → Use <button> for actions, <a> for navigation

8. Keyboard Accessibility

**Test Steps:**

  1. Complete entire critical user path using Tab only
  2. Try to escape from modals with Escape
  3. Try to close dropdowns with Escape
  4. Verify focus visible at all times

**Expected Results:**

  • [ ] All interactive elements reachable via Tab
  • [ ] Tab order matches visual order (left-to-right, top-to-bottom)
  • [ ] Focus visible on all interactive elements (2px+ outline)
  • [ ] Escape key closes modals, dropdowns, menus
  • [ ] Enter/Space activate buttons, links, checkboxes
  • [ ] Arrow keys work in dropdowns, menus, lists

**Common Issues:**

  • ❌ Focus not visible → Add :focus { outline: 2px solid blue; }
  • ❌ Wrong tab order → Ensure DOM order matches visual order
  • ❌ Keyboard trap → Ensure Escape works, focus can exit
  • ❌ Skip link invisible → Make skip link visible on :focus

---

VoiceOver Testing (macOS)

Setup

  1. **Enable VoiceOver:**
  • Press Cmd+F5 to toggle VoiceOver on/off
  • Or: System Settings → Accessibility → VoiceOver → Enable
  1. **Configure Settings:**
  • VoiceOver Utility → Speech → Default voice and rate
  • Set verbosity to "Medium" (balanced detail)
  • Enable "Navigation verbosity" → "High" (more detail)
  1. **Choose Browser:**
  • **Safari** (recommended) - Best VoiceOver integration
  • **Chrome** (acceptable) - Generally good support
  • **Firefox** (not recommended) - Poor VoiceOver support
  1. **Test Environment:**
  • Test on macOS 13 (Ventura) or later
  • Use external speakers or headphones
  • Close other apps that might interfere

Key VoiceOver Commands

**Global Commands (work in any application):**

CommandActionNotes
Cmd+F5Toggle VoiceOverEnable/disable screen reader
Cmd+Fn+F5Toggle VoiceOver (on laptops)Alternate command
VO+;Stop speechSilence current speech
VO+Cmd+;Restart VoiceOverReload VoiceOver settings
VO+Cmd+\`Open VoiceOver UtilityConfigure settings

**Note:** VO = Ctrl+Option (hold both keys together)

**Navigation Commands (in browser):**

CommandActionNotes
VO+RightNext itemMove to next element
VO+LeftPrevious itemMove to previous element
VO+DownInteract with elementEnter "interact" mode
VO+UpStop interactionExit "interact" mode
VO+Shift+DownRead allStart reading from current position
VO+Shift+RightRead next sentenceRead sentence by sentence

**Heading Navigation:**

CommandActionNotes
VO+HNext headingJump to next heading
VO+Shift+HPrevious headingJump to previous heading
VO+Cmd+HJump to heading levelChoose heading level 1-6

**Rotor Navigation (most important VoiceOver feature):**

CommandActionNotes
VO+UOpen rotorShows navigation menu
VO+U then HHeadings in rotorJump by headings
VO+U then LLandmarks in rotorJump by landmarks
VO+U then IItems in rotorAll links, headings, etc.
VO+IItem chooserSearchable list of all items
Left/Right in rotorNavigate rotor optionsCycle through rotor types

**Table Navigation:**

CommandActionNotes
VO+]Next tableJump to next table
VO+[Previous tableJump to previous table
VO+Cmd+]Table rowNavigate table by rows
VO+Down (in table)Interact with tableEnter table navigation mode

**Form Navigation:**

CommandActionNotes
VO+Cmd+JNext form fieldJump to next input
TabNext focusableMove to next focusable element
Shift+TabPrevious focusableMove to previous focusable
SpaceActivate buttonToggle checkbox, activate button
EnterActivate link/buttonFollow link, submit form

**Web Item-Specific Commands:**

CommandActionNotes
VO+Cmd+XNext linkJump to next link
VO+Shift+Cmd+XPrevious linkJump to previous link
VO+CNext visited linkJump to next visited link
VO+Shift+CPrevious visited linkJump to previous visited link

Test Scenarios for VoiceOver

1. Page Load

**Test Steps:**

  1. Navigate to page URL in Safari
  2. Listen to initial announcement

**Expected Results:**

  • [ ] Page title announced
  • [ ] "Web content" announced (entire page region)
  • [ ] Number of landmarks (if configured)
  • [ ] Heading structure available in rotor (VO+U → "Headings")
  • [ ] Can navigate by landmarks via rotor

**Common Issues:**

  • ❌ No page title → Add <title>Page Name</title>
  • ❌ No landmarks → Add <main>, <nav>, <header>, <footer> with aria-label
  • ❌ No headings → Add heading structure for navigation

2. Navigation with Rotor

**Test Steps:**

  1. Press VO+U to open rotor
  2. Use Left/Right arrows to choose "Headings"
  3. Use Up/Down arrows to navigate headings
  4. Press VO+U again, choose "Landmarks"
  5. Navigate landmarks

**Expected Results:**

  • [ ] Rotor shows "Headings" option
  • [ ] Rotor shows "Landmarks" option
  • [ ] Rotor shows "Links" option
  • [ ] Heading levels announced in rotor
  • [ ] Can jump directly to any heading or landmark
  • [ ] Landmarks have descriptive names (not "region")

**Common Issues:**

  • ❌ Rotor missing options → Ensure semantic HTML (headings, landmarks)
  • ❌ Vague landmark names → Add aria-label="Main content" to <main>
  • ❌ No heading structure → Add proper heading hierarchy

3. Forms

**Test Steps:**

  1. Navigate to form using rotor or headings
  2. Press VO+Cmd+J to jump between form fields
  3. Fill out form (interact with each input)
  4. Submit form

**Expected Results:**

  • [ ] Label announced BEFORE input (when landing on input)
  • [ ] "Edit text" or "checkbox" announced (input type)
  • [ ] Required field indicated ("required", "star")
  • [ ] Placeholder NOT announced as label (it's just a hint)
  • [ ] Error messages announced immediately after appearing
  • [ ] Validation feedback provided

**Common Issues:**

  • ❌ No label announced → Add <label for="id"> + id="id" on input
  • ❌ Placeholder as label → Add proper label, keep placeholder as hint only
  • ❌ Errors not announced → Add role="alert" to error container + aria-live
  • ❌ Required not indicated → Add aria-required="true" + visual "*"

4. Dynamic Content (Modals, Toasts, Live Updates)

**Test Steps:**

  1. Trigger modal open (button, link)
  2. Listen to announcement
  3. Interact with modal (VO+Down)
  4. Close modal
  5. Observe focus behavior
  6. Trigger toast/notification
  7. Trigger dynamic content update

**Expected Results:**

  • [ ] Modal announced ("dialog appeared", "window appeared")
  • [ ] Focus moves to modal title or first focusable element
  • [ ] Focus trapped in modal (can't tab outside)
  • [ ] Modal close announced
  • [ ] Focus returns to trigger button after close
  • [ ] Toast notifications announced
  • [ ] Loading states announced
  • [ ] New list items announced

**Common Issues:**

  • ❌ Modal not announced → Add role="dialog" + aria-modal="true" + aria-labelledby
  • ❌ Focus not trapped → Implement focus trap (JavaScript required)
  • ❌ Focus not restored → Save trigger element, restore focus on close
  • ❌ Toast not announced → Add role="status" or role="alert" + aria-live="polite"
  • ❌ Loading not announced → Add aria-live="polite" to loading indicator

5. Tables

**Test Steps:**

  1. Navigate to table (VO+])
  2. Interact with table (VO+Down)
  3. Navigate cells with arrow keys
  4. Listen to header announcements

**Expected Results:**

  • [ ] Table announced as table
  • [ ] Table dimensions announced (rows, columns)
  • [ ] Column/row headers announced when navigating
  • [ ] Cell coordinates announced (optional but helpful)
  • [ ] Can navigate entire table with arrow keys
  • [ ] Sorting/filtering controls announced

**Common Issues:**

  • ❌ No headers → Add <th scope="col"> or <th scope="row">
  • ❌ Layout table → Add role="presentation" to layout tables
  • ❌ Nested tables → Flatten to single table structure
  • ❌ Coordinates missing → Add proper header associations

**Test Steps:**

  1. Navigate through page with VO+Right
  2. Listen to link/button announcements
  3. Open rotor (VO+U) → "Links"
  4. Navigate through all links

**Expected Results:**

  • [ ] Link text announced clearly
  • [ ] "Link" announced after text (distinguish from buttons)
  • [ ] "Button" announced for button elements
  • [ ] Icon-only buttons have aria-label announced
  • [ ] Visited links indicated (if configured)
  • [ ] Link destination is clear from text

**Common Issues:**

  • ❌ "Click here" links → Use descriptive text: "View pricing"
  • ❌ Icon button no label → Add aria-label="Close dialog"
  • ❌ Ambiguous link text → Use descriptive destination
  • ❌ Button used as link → Use <a> for navigation, <button> for actions

7. Keyboard Accessibility

**Test Steps:**

  1. Navigate entire page using Tab only
  2. Close modals with Escape
  3. Close dropdowns with Escape
  4. Verify focus visible at all times

**Expected Results:**

  • [ ] All interactive elements reachable via Tab
  • [ ] Tab order matches visual order
  • [ ] Focus indicator visible (thick outline, background change)
  • [ ] Escape closes modals, dropdowns, menus
  • [ ] Enter/Space activate buttons, links
  • [ ] Arrow keys work in dropdowns, menus, lists

**Common Issues:**

  • ❌ Focus not visible → Add :focus { outline: 3px solid blue; outline-offset: 2px; }
  • ❌ Wrong tab order → Fix DOM order to match visual order
  • ❌ Keyboard trap → Ensure all interactive elements exitable with Escape
  • ❌ Skip link hidden → Make skip link visible on :focus

---

Critical User Paths to Test

Authentication

**Login Form:**

  • [ ] Email input label announced ("Email input")
  • [ ] Password input label announced ("Password input")
  • [ ] Submit button announced ("Log in button")
  • [ ] Validation errors announced ("Invalid email")
  • [ ] "Forgot password?" link destination clear
  • [ ] Can complete login with keyboard only

**Password Reset:**

  • [ ] Instructions announced clearly
  • [ ] Email input label announced
  • [ ] Submit button announced
  • [ ] Success message announced ("Email sent")
  • [ ] Back to login link available

**Signup Form:**

  • [ ] All fields labeled (name, email, password, etc.)
  • [ ] Required fields indicated
  • [ ] Password strength announced (if implemented)
  • [ ] Terms of service checkbox label clear
  • [ ] Submit button announced
  • [ ] Validation errors announced per field

Agent Management

**Agent List (Table):**

  • [ ] Table purpose announced ("Agents table, 5 columns")
  • [ ] Column headers announced (Name, Status, Actions)
  • [ ] Row navigation works (up/down arrows)
  • [ ] Can navigate to agent details
  • [ ] Action buttons labeled ("Edit", "Delete")
  • [ ] Sortable columns indicate sort direction

**Agent Creation Form:**

  • [ ] Multi-step form progress announced ("Step 1 of 3")
  • [ ] Each step heading announced
  • [ ] Form fields labeled clearly
  • [ ] Validation feedback provided
  • [ ] Back/Next navigation buttons labeled
  • [ ] Can complete form with keyboard only

**Agent Configuration:**

  • [ ] Skill selection checkboxes labeled
  • [ ] Toggle switches announced ("enabled", "disabled")
  • [ ] Save/Cancel buttons labeled
  • [ ] Configuration changes announced

Canvas/Skills Marketplace

**Marketplace (Cards):**

  • [ ] Card structure clear (heading, description, install button)
  • [ ] Install buttons labeled ("Install skill", "Learn more")
  • [ ] Search input label announced
  • [ ] Filter controls announced
  • [ ] Can navigate marketplace with keyboard

**Skill Install Confirmation:**

  • [ ] Modal announced ("Install skill dialog")
  • [ ] Skill name announced
  • [ ] Confirm button labeled ("Install", "Cancel")
  • [ ] Focus returns to trigger after close

Billing

**Usage Data Table:**

  • [ ] Table headers announced (Date, Usage, Cost)
  • [ ] Data cells readable
  • [ ] Sortable columns indicate direction
  • [ ] Pagination controls labeled
  • [ ] Export button labeled ("Export CSV")

**Pricing Comparison:**

  • [ ] Plan names announced (Free, Solo, Team)
  • [ ] Feature lists clear (checkmarks, x marks)
  • [ ] Pricing differences clear
  • [ ] Subscribe buttons labeled
  • [ ] Can compare plans easily

Admin

**Tenant List (Table):**

  • [ ] Table headers announced
  • [ ] Row actions labeled ("View", "Edit", "Suspend")
  • [ ] Status indicators announced ("Active", "Suspended")
  • [ ] Can navigate and perform actions with keyboard

**User Management:**

  • [ ] User list table navigable
  • [ ] Status changes announced
  • [ ] Confirmation dialogs for destructive actions
  • [ ] Error messages announced

---

Edge Cases to Verify

Custom Components

**Custom Dropdowns (Select alternatives):**

  • [ ] Expand/collapse announced ("menu expanded", "menu collapsed")
  • [ ] Current value announced
  • [ ] Options navigable with arrow keys
  • [ ] Selection announced
  • [ ] Escape closes dropdown
  • [ ] Focus management correct

**Custom Checkboxes:**

  • [ ] Checked state announced ("checked", "not checked")
  • [ ] Label announced before checkbox
  • [ ] Space toggles checkbox
  • [ ] Visual state matches announced state

**Toast Notifications:**

  • [ ] Toast announced automatically (live region)
  • [ ] Toast message clear
  • [ ] Dismiss button labeled (if present)
  • [ ] Auto-dismiss after timeout (optional)
  • [ ] Multiple toasts announced sequentially

**Auto-suggest / Autocomplete:**

  • [ ] Input label announced
  • [ ] Options announced when typing
  • [ ] Number of options announced ("5 suggestions available")
  • [ ] Can navigate options with arrow keys
  • [ ] Selection announced

Keyboard + Screen Reader

**Tab Order:**

  • [ ] Tab order matches visual order (left-to-right, top-to-bottom)
  • [ ] Skip links work (jump to main content)
  • [ ] Focus visible at all times
  • [ ] Focus announcements accurate
  • [ ] No keyboard traps (can't exit component)

**Escape Key Behavior:**

  • [ ] Modals close with Escape
  • [ ] Dropdowns/menus close with Escape
  • [ ] Focus returns to trigger after close
  • [ ] Escape announced appropriately

**Focus Management:**

  • [ ] Focus moves to modal when opened
  • [ ] Focus trapped in modal (can't tab out)
  • [ ] Focus returns to trigger after close
  • [ ] Focus moves to error message after validation fails
  • [ ] Focus moves to new content after navigation

Dynamic Updates

**Loading States:**

  • [ ] "Loading" announced when fetching data
  • [ ] "Loaded" announced when complete
  • [ ] Spinner announced (if visible)
  • [ ] Progress bars updated (live region)

**New List Items:**

  • [ ] New items in list announced
  • [ ] Number of new items announced
  • [ ] Can navigate to new items
  • [ ] Updates don't interrupt current task

**Live Chat / Notifications:**

  • [ ] New messages announced (live region)
  • [ ] Sender announced
  • [ ] Message content announced
  • [ ] Notification sound (optional)

---

Testing Checklist

Quarterly Audit (Full Manual Testing)

**Setup:**

  1. [ ] Test on Windows with NVDA + Firefox
  2. [ ] Test on macOS with VoiceOver + Safari
  3. [ ] Use external speakers/headphones
  4. [ ] Allow 4-6 hours for full audit

**Execution:**

**NVDA (Windows):**

  1. [ ] Run through all NVDA test scenarios (above)
  2. [ ] Test all critical user paths
  3. [ ] Test edge cases (custom components, dynamic content)
  4. [ ] Document all violations in accessibility tracker

**VoiceOver (macOS):**

  1. [ ] Run through all VoiceOver test scenarios (above)
  2. [ ] Test all critical user paths
  3. [ ] Test edge cases (custom components, dynamic content)
  4. [ ] Document all violations in accessibility tracker

**Post-Testing:**

  1. [ ] Compile violation report (see VIOLATION_REPORTING.md)
  2. [ ] Prioritize: critical > serious > moderate
  3. [ ] Create GitHub issues with a11y label
  4. [ ] Track remediation progress
  5. [ ] Schedule re-testing after fixes

Before Major Release

**Timeline:** 1-2 weeks before release

**Duration:** 2-4 hours

  1. [ ] Run automated suite first (npm run test:a11y:full)
  2. [ ] Generate violation report (npm run a11y:report)
  3. [ ] Test new UI features with NVDA + VoiceOver
  4. [ ] Verify previous violations fixed
  5. [ ] Document new violations
  6. [ ] Fix critical/serious violations before release
  7. [ ] Schedule moderate violations for next sprint

When Introducing New UI Patterns

**Trigger:** New component, new layout, new interaction pattern

**Duration:** 1-2 hours

  1. [ ] Test new component with NVDA
  2. [ ] Test new component with VoiceOver
  3. [ ] Verify keyboard navigation works
  4. [ ] Verify focus management correct
  5. [ ] Add jest-axe component test if missing
  6. [ ] Add E2E a11y test if critical path
  7. [ ] Document any violations found

---

Common Issues and Fixes

IssueCauseFixExample
Not announcedMissing aria-liveAdd aria-live="polite"<div aria-live="polite">{message}</div>
No labelMissing for/idAdd label with for attribute<label for="email">Email</label><input id="email">
Confusing navigationNested landmarksFlatten structureUse single <main>, avoid nesting <section>
Skipped by screen readerTabindex=-1Remove for interactive elementsDon't use tabindex=-1 on buttons/links
Modal not announcedMissing role dialogAdd role="dialog"<div role="dialog" aria-modal="true">
Focus not trappedMissing focus trapImplement focus trapJavaScript focus management
Alt text missingMissing alt attributeAdd alt attribute<img src="photo.jpg" alt="Team photo">
Heading skippedMissing heading levelAdd all heading levelsDon't skip from h1 to h3
Low contrastColor fails 4.5:1 ratioIncrease contrastChange #999 to #595959 on white
Form errors not announcedMissing aria-live on errorsAdd role="alert"<div role="alert">{errors}</div>

---

Resources

**NVDA:**

  • Download: https://www.nvaccess.org/download/
  • Documentation: https://www.nvaccess.org/documentation/
  • Keyboard Commands: https://www.nvaccess.org/files/nvda/documentation/keyCommands.html

**VoiceOver:**

  • Built into macOS (Cmd+F5 to enable)
  • Apple Documentation: https://www.apple.com/accessibility/voiceover/
  • VoiceOver Commands: https://www.apple.com/voiceover/info/guide/

**WCAG 2.1 AA:**

  • Quick Reference: https://www.w3.org/WAI/WCAG21/quickref/
  • Understanding WCAG: https://www.w3.org/WAI/WCAG21/Understanding/

**Testing Tools:**

  • axe DevTools (browser extension): https://www.deque.com/axe/devtools/
  • WAVE (browser extension): https://wave.webaim.org/
  • Lighthouse (built into Chrome): chrome://lighthouse

---

**Procedure Version:** 1.0

**Last Updated:** 2026-03-22

**Next Review:** 2026-06-22 (Quarterly)

**Owner:** QA Team + Development Team

**Related Documentation:**

  • docs/accessibility/THREE_TIER_STRATEGY.md (overall strategy)
  • docs/accessibility/VIOLATION_REPORTING.md (violation format)
  • docs/accessibility/MANUAL_TESTING_CHECKLIST.md (checklist)